package lib.core.view
{
	import flash.utils.Dictionary;
	
	import lib.config.ApplicationNotifications;
	import lib.core.com.BaseApplication;
	import lib.core.com.modules.BaseModule;
	import lib.core.controller.RequestUrlInfo;
	
	import mx.events.FlexEvent;
	import mx.events.ModuleEvent;
	import mx.modules.IModuleInfo;
	import mx.modules.ModuleManager;
	
	import org.puremvc.as3.interfaces.IMediator;
	import org.puremvc.as3.interfaces.INotification;
	import org.puremvc.as3.patterns.mediator.Mediator;
	
	public class BaseModuleLoaderMediator extends Mediator implements IMediator
	{
		private var _currentUrl:RequestUrlInfo;
		private var _currentModule:IModuleInfo;
		private var _cm:BaseModule;
		private var _requestedModuleUrl:String;
		
		private var _cachedModules:Dictionary = new Dictionary();
		
		public function get app():BaseApplication
		{
			return this.viewComponent as BaseApplication;
		}
		
		public function BaseModuleLoaderMediator(name:String, viewComponent:BaseApplication)
		{
			super(name, viewComponent);
		}
		
		override public function listNotificationInterests():Array
		{
			return [
				ApplicationNotifications.URLRULE_VALID,
				ApplicationNotifications.URLRULE_INVALID
			];
		}
		
		override public function handleNotification(notification:INotification):void
		{
			switch (notification.getName())
			{
				case ApplicationNotifications.URLRULE_VALID:
				case ApplicationNotifications.URLRULE_INVALID:
					this._currentUrl = notification.getBody() as RequestUrlInfo;
					this.loadModule(this._currentUrl);
				break;
			}
		}
		
		protected function loadModule(request:RequestUrlInfo):void
		{
			this._requestedModuleUrl = "modules/"+request.actualModule+"Module.swf";
			
			var module:BaseModule;
			
			// hide any active module
			if (this._cm != null)
			{
				this.app.deactivateModules();
			}
			
			// if we have the requested module cached then we can load it from there
			if (this._cachedModules.hasOwnProperty(this._requestedModuleUrl))
			{
				module = this._cachedModules[this._requestedModuleUrl] as BaseModule;
				this._cm = module;
				module.includeInLayout = true;
				module.visible = true;
				this.sendModuleStartup(module);
			} 
			else 
			{
				// this is a new module, we will load the SWF file and report the 
				// loading progress to the application
				this._currentModule = ModuleManager.getModule(this._requestedModuleUrl);
				this._currentModule.addEventListener(ModuleEvent.UNLOAD, onModuleUnload);
				this._currentModule.addEventListener(ModuleEvent.READY, onModuleReady);
	            this._currentModule.addEventListener(ModuleEvent.PROGRESS, onModuleProgress);
				this._currentModule.addEventListener(ModuleEvent.SETUP, onModuleSetup);
				this._currentModule.load();
			}
		}
				
		protected function onModuleReady(e:ModuleEvent):void
		{
			// The module has been loaded successfully
			var moduleInfo:IModuleInfo = e.currentTarget as IModuleInfo;
			var module:BaseModule = moduleInfo.factory.create() as BaseModule;
			// Add a creation complete event handler so that we can dispatch the module start up notification
			module.addEventListener(FlexEvent.CREATION_COMPLETE, onModuleCreationComplete);
			// Cache the current module
			this._cachedModules[this._requestedModuleUrl] = module;
			this._cm = module;
			// Add the module to the display list		
			app.container.addChildAt(module, 0);
		}
		
		protected function onModuleUnload(e:ModuleEvent):void
		{
			var moduleInfo:IModuleInfo = e.currentTarget as IModuleInfo;
			var module:BaseModule = moduleInfo.factory.create() as BaseModule;
			moduleInfo.release();
		}
		protected function onModuleSetup(e:ModuleEvent):void
		{
			// The module is setup and ready to be loaded. We notify the application of this state
			this.app.onModuleSetup(e);
		}
		protected function onModuleProgress(e:ModuleEvent):void
		{
			// The module is being loaded. We notify the application of the progress
			this.app.onModuleLoading(e);
		}
		protected function onModuleCreationComplete(e:FlexEvent):void
		{
			// The module was added to the display list and was validated.
			// First we notify the application that this occured and then send out the module startup notification
			this.app.onModuleLoaded();
			this.sendModuleStartup(e.currentTarget as BaseModule);	
		}
		
		protected function sendModuleStartup(module:BaseModule = null):void
		{
			if (module == null)
			{
				module = this._currentModule.factory.create() as BaseModule;
			}
			this.sendNotification(ApplicationNotifications.MODULE_STARTUP, module, this._currentUrl.rawUrl);	
		}
	}
}